#ifndef _TREENODE_
#define _TREENODE_

#include <set>
#include <map>
#include <string>
#include "ExpressionType.h"

class GeneralVisitor;
class Variable;             // dopredna deklarace kvuli metode CheckVariables
class FunctionDefinition;   // dopredna deklarace kvuli metode CheckFunctionCalls
class ClassDefinition;      // dopredna deklarace kvuli metode CheckClassConstructions
class ReturnStatement;      // dopredna deklarace kvuli GetFirstReturnStatement

using namespace std;

class TreeNode
{
public:
    TreeNode()          { fIsLeftValue = false; }
    virtual ~TreeNode() { }
    virtual void Accept(GeneralVisitor*) = 0;
    virtual void CheckVariables(set<string>&, string) { }
    virtual void CheckFunctionCalls(set<FunctionDefinition*>&, string) { }
    virtual void CheckClassConstructions(set<ClassDefinition*>&, string) { }
    virtual void CheckExpressionTypes(map<string, ExpressionType*>&, string) { }
    virtual string GetVarName() { return ""; }
    virtual bool IsClassField() { return false; }
    virtual bool IsArrayAccess(){ return false; }
    virtual void SetLeftValue() { fIsLeftValue = true; }
    virtual bool IsLeftValue()  { return fIsLeftValue; }

    // Toto chce trochu objasneni.
    // Vrati typ vyrazu.
    // Ale pozor, vzdy vytvari novy objekt. I pokud je to promenna a najde se v iVarTypes, tak vrati kopii
    // toho, co je v iVarTypes.
    // Duvod: jine uzly nez Variable musi vzdy vytvorit novy objekt (nemaji zadny seznam, odkud by to vzaly).
    // --->>> Proto volajici musi zajistit, aby se vracena hodnota smazala, abychom nemeli uniky pameti. <<<---
    // A proto Variable musi vratit kopii - jinak by se smazala hodnota, kterou by se pak nekdo snazil jeste pouzit.
    virtual ExpressionType* GetType(map<string, ExpressionType*>&, string iParentName)
    {
        return new ExpressionType(Undefined);
    }

    // Svizelna situace... FunctionDefinition ma telo funkce jako Statement* a potrebujeme mit moznost nejak
    // dostat uzel typu ReturnExpression* z tela funkce (pokud tam je). Pomoci tehle metody je to elegantni, i kdyz je mozna
    // trochu prasarna, ze se tu odkazuju na potomka Statement*... ale nic lepsiho me nenapada (mozna by se dalo
    // pouzit RTTI a dynamic_cast a podobne veci, ale to mi pripada jako jeste vetsi veprovina).
    virtual ReturnStatement* GetFirstReturnStatement() { return 0; }

protected:
    bool fIsLeftValue;
};

#endif
